//////////////////////////////////////////////////////////////////////////////////
// 本程序只供学习使用，未经作者许可，不得用于其它任何用途
// 测试硬件：单片机STM32F103RCT6,正点原子MiniSTM32开发板,主频72MHZ，晶振12MHZ
// QDtech-TFT液晶驱动 for STM32 IO模拟
// xiao冯@ShenZhen QDtech co.,LTD
// 公司网站:www.qdtft.com
// 淘宝网站：http://qdtech.taobao.com
// wiki技术网站：http://www.lcdwiki.com
// 我司提供技术支持，任何技术问题欢迎随时交流学习
// 固话(传真) :+86 0755-23594567
// 手机:15989313508（冯工）
// 邮箱:lcdwiki01@gmail.com    support@lcdwiki.com    goodtft@163.com
// 技术支持QQ:3002773612  3002778157
// 技术交流QQ群:324828016
// 创建日期:2018/08/09
// 版本：V1.0
// 版权所有，盗版必究。
// Copyright(C) 深圳市全动电子技术有限公司 2018-2028
// All rights reserved
// 移植作者：假的太真  https://github.com/jiadetaizhen
/****************************************************************************************************
**************************************************************************************************/
/* @attention
 *
 * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
 * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
 * TIME. AS A RESULT, QD electronic SHALL NOT BE HELD LIABLE FOR ANY
 * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
 * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
 * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
 **************************************************************************************************/
#include "lcd.h"
#include "stdlib.h"
#include "delay.h"
#include "SPI.h"
#include "dma.h"
#include "main.h"


// 添加DMA配置结构
typedef struct {
    int8_t spi_sz;
    int8_t dma_sz;
    int8_t dma_mem_inc;
} dma_config_t;

static dma_config_t dma_config = {
    .spi_sz = -1,
    .dma_sz = -1,
    .dma_mem_inc = -1,
};

// SPI和DMA数据宽度、地址递增模式常量定义
#define mode_16bit    1      // 16位模式
#define mode_8bit     0      // 8位模式
#define mem_increase  1      // 内存递增
#define mem_fixed     0      // 内存固定

/**
 * @brief 设置SPI数据宽度
 * @param size: 0=8位, 1=16位
 */
static void LCD_SetSPISize(int8_t size)
{
    if(dma_config.spi_sz != size) {
        __HAL_SPI_DISABLE(&LCD_SPI_HANDLE);
        dma_config.spi_sz = size;
        
        if(size == mode_16bit) {
            LCD_SPI_HANDLE.Init.DataSize = SPI_DATASIZE_16BIT;
        } else {
            LCD_SPI_HANDLE.Init.DataSize = SPI_DATASIZE_8BIT;
        }
        HAL_SPI_Init(&LCD_SPI_HANDLE);
    }
}

#ifdef USE_DMA
/**
 * @brief 配置DMA传输模式
 * @param memInc: 内存地址是否递增
 * @param size: 数据宽度(0=8位, 1=16位)
 */
void LCD_SetDMAMode(uint8_t memInc, uint8_t size)
{
    LCD_SetSPISize(size);
    
    // 如果DMA配置发生变化，重新配置DMA
    if(dma_config.dma_sz != size || dma_config.dma_mem_inc != memInc) {
        dma_config.dma_sz = size;
        dma_config.dma_mem_inc = memInc;
        
        __HAL_DMA_DISABLE(LCD_SPI_HANDLE.hdmatx);
        
        // 等待DMA完全禁用
        while((LCD_SPI_HANDLE.hdmatx->Instance->CCR & DMA_CCR_EN) != RESET);
        
        // 配置内存递增模式
        if(memInc == mem_increase) {
            LCD_SPI_HANDLE.hdmatx->Init.MemInc = DMA_MINC_ENABLE;
            LCD_SPI_HANDLE.hdmatx->Instance->CCR |= DMA_CCR_MINC;
        } else {
            LCD_SPI_HANDLE.hdmatx->Init.MemInc = DMA_MINC_DISABLE;
            LCD_SPI_HANDLE.hdmatx->Instance->CCR &= ~(DMA_CCR_MINC);
        }
        
        // 配置数据宽度
        if(size == mode_16bit) {
            LCD_SPI_HANDLE.hdmatx->Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
            LCD_SPI_HANDLE.hdmatx->Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
            LCD_SPI_HANDLE.hdmatx->Instance->CCR = (LCD_SPI_HANDLE.hdmatx->Instance->CCR & ~(DMA_CCR_PSIZE_Msk | DMA_CCR_MSIZE_Msk)) |
                                                   (1<<DMA_CCR_PSIZE_Pos | 1<<DMA_CCR_MSIZE_Pos);
        } else {
            LCD_SPI_HANDLE.hdmatx->Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
            LCD_SPI_HANDLE.hdmatx->Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
            LCD_SPI_HANDLE.hdmatx->Instance->CCR = (LCD_SPI_HANDLE.hdmatx->Instance->CCR & ~(DMA_CCR_PSIZE_Msk | DMA_CCR_MSIZE_Msk));
        }
    }
}
#endif

/**
 * @brief 使用DMA传输数据
 * @param data: 数据指针
 * @param size: 数据大小
 */
void LCD_WriteData_DMA(uint8_t *data, uint16_t size)
{
#ifdef USE_DMA
    // 检查数据指针有效性
    if(data == NULL || size == 0) {
        return;
    }
    
    LCD_CS_CLR;
    LCD_RS_SET;

    HAL_SPI_Transmit_DMA(&LCD_SPI_HANDLE, data, size);

    while(HAL_DMA_GetState(LCD_SPI_HANDLE.hdmatx) != HAL_DMA_STATE_READY);


    LCD_CS_SET;
#else
    // 非DMA模式，使用原有方法
    LCD_CS_CLR;
    LCD_RS_SET;
    HAL_SPI_Transmit(&LCD_SPI_HANDLE, data, size, HAL_MAX_DELAY);
    LCD_CS_SET;
#endif
}

/**
 * @brief 以DMA或SPI填充指定颜色到LCD（16位RGB565），支持大块分段发送
 * @param color: 18位RGB666颜色
 * @param pixels: 要填充的像素数
 *
 * 针对像素数量较大的情况进行分块（单次最大65535），支持DMA和非DMA两种方式
 */
void LCD_FillColor_DMA(uint16_t color, uint32_t pixels)
{
    // RGB565转为RGB666 (ILI9488格式: RRRRRR-- GGGGGG-- BBBBBB--)
    // 提取RGB565的各分量
    uint8_t r5 = (color >> 11) & 0x1F;  // 5位红色
    uint8_t g6 = (color >> 5) & 0x3F;   // 6位绿色
    uint8_t b5 = color & 0x1F;          // 5位蓝色

    // 转换为6位格式并左移2位对齐到高6位
    uint8_t red18   = ((r5 << 1) | (r5 >> 4)) << 2;  // 5位->6位->左移2位
    uint8_t green18 = g6 << 2;                        // 6位->左移2位
    uint8_t blue18  = ((b5 << 1) | (b5 >> 4)) << 2;  // 5位->6位->左移2位

    // 设置 LCD 数据写模式
    LCD_CS_CLR;
    LCD_RS_SET;
    
#ifdef USE_DMA
    // 使用DMA递增模式发送，需要预填充缓冲区
    // 定义一个较大的缓冲区用于批量传输（每次最多512像素 = 1536字节）
    #define DMA_BUFFER_PIXELS 512
    static uint8_t dma_buffer[DMA_BUFFER_PIXELS * 3];
    
    // 预填充缓冲区（只需填充一次）
    for(uint16_t i = 0; i < DMA_BUFFER_PIXELS; i++) {
        dma_buffer[i * 3 + 0] = red18;
        dma_buffer[i * 3 + 1] = green18;
        dma_buffer[i * 3 + 2] = blue18;
    }
    
    // 设置DMA为递增模式和8位模式
    LCD_SetDMAMode(1, 0);  // mem_increase=1, mode_8bit=0
    
    // 分块发送
    while (pixels > 0) {
        uint32_t chunk_pixels = (pixels > DMA_BUFFER_PIXELS) ? DMA_BUFFER_PIXELS : pixels;
        uint16_t bytes_to_send = 3 * chunk_pixels;
        
        if (HAL_SPI_Transmit_DMA(&LCD_SPI_HANDLE, dma_buffer, bytes_to_send) == HAL_OK) {
            // 等待DMA传输完成
            while (HAL_DMA_GetState(LCD_SPI_HANDLE.hdmatx) != HAL_DMA_STATE_READY);
        }
        pixels -= chunk_pixels;
    }
    
    LCD_CS_SET;
#else
    // 非DMA模式，循环填充
    uint8_t pixel_buf[3] = {red18, green18, blue18};
    while (pixels > 0) {
        uint32_t chunk_pixels = (pixels > 21845) ? 21845 : pixels;
        for (uint32_t i = 0; i < chunk_pixels; i++) {
            HAL_SPI_Transmit(&LCD_SPI_HANDLE, pixel_buf, 3, HAL_MAX_DELAY);
        }
        pixels -= chunk_pixels;
    }
    LCD_CS_SET;
#endif
}


/**
 * @brief 逐个像素处理/适配(将color_p每个像素RGB565转为ILI9488所需的RGB666格式，批量双缓冲DMA发送)
 * @param color_p: 指向LVGL输出的RGB565缓冲，每像素2字节
 * @param pixels: 需要传输的像素数量
 *
 * 使用双缓冲方式转换和DMA发送，每次填满一个缓冲区后批量DMA传输，提升效率
 */
void LCD_FillColor_PerPixel(uint16_t *color_p, uint32_t pixels)
{
    #define PIXEL_BATCH_SIZE 1024
    static uint8_t buf1[PIXEL_BATCH_SIZE * 3] = {0};
    static uint8_t buf2[PIXEL_BATCH_SIZE * 3] = {0};
    uint8_t *cur_buf;
    uint8_t *next_buf;

    LCD_CS_CLR;
    LCD_RS_SET;

    uint32_t remain = pixels;
    uint32_t processed = 0;
    uint8_t toggle = 0;

    while (remain > 0) {
        uint32_t this_batch = (remain > PIXEL_BATCH_SIZE) ? PIXEL_BATCH_SIZE : remain;
        cur_buf = toggle ? buf2 : buf1;
        next_buf = toggle ? buf1 : buf2;

        // 填充当前缓冲区数据
        for (uint32_t i = 0; i < this_batch; i++) {
            uint16_t color = color_p[processed + i];
            uint8_t r5 = (color >> 11) & 0x1F;
            uint8_t g6 = (color >> 5)  & 0x3F;
            uint8_t b5 = color & 0x1F;
            uint8_t r6 = ((r5 << 1) | (r5 >> 4)) << 2;
            uint8_t g6_ = g6 << 2;
            uint8_t b6 = ((b5 << 1) | (b5 >> 4)) << 2;

            cur_buf[3 * i + 0] = r6;
            cur_buf[3 * i + 1] = g6_;
            cur_buf[3 * i + 2] = b6;
        }

        // 使用DMA发送当前缓冲区数据
        if (HAL_SPI_Transmit_DMA(&LCD_SPI_HANDLE, cur_buf, this_batch * 3) == HAL_OK) {
            // 等待DMA传输完成
            while (HAL_DMA_GetState(LCD_SPI_HANDLE.hdmatx) != HAL_DMA_STATE_READY);
        }

        processed += this_batch;
        remain -= this_batch;
        toggle = !toggle;
    }

    LCD_CS_SET;
}




// 管理LCD重要参数
// 默认为竖屏
_lcd_dev lcddev;

// 画笔颜色,背景颜色
uint16_t POINT_COLOR = 0x0000, BACK_COLOR = 0xFFFF;
uint16_t DeviceCode;

/*****************************************************************************
 * @name       :void LCD_WR_REG(uint8_t data)
 * @date       :2018-08-09
 * @function   :Write an 8-bit command to the LCD screen
 * @parameters :data:Command value to be written
 * @retvalue   :None
 ******************************************************************************/
void LCD_WR_REG(uint8_t data)
{
	LCD_CS_CLR;
	LCD_RS_CLR;
	HAL_SPI_Transmit(&LCD_SPI_HANDLE, &data, 1, 1000);
	//    SPIv_WriteData(data);
	LCD_CS_SET;
}

/*****************************************************************************
 * @name       :void LCD_WR_DATA(uint8_t data)
 * @date       :2018-08-09
 * @function   :Write an 8-bit data to the LCD screen
 * @parameters :data:data value to be written
 * @retvalue   :None
 ******************************************************************************/
void LCD_WR_DATA(uint8_t data)
{
    LCD_CS_CLR;
    LCD_RS_SET;
    HAL_SPI_Transmit(&LCD_SPI_HANDLE, &data, 1, HAL_MAX_DELAY);
    LCD_CS_SET;
}

/*****************************************************************************
 * @name       :void LCD_WriteReg(uint8_t LCD_Reg, uint16_t LCD_RegValue)
 * @date       :2018-08-09
 * @function   :Write data into registers
 * @parameters :LCD_Reg:Register address
				LCD_RegValue:Data to be written
 * @retvalue   :None
******************************************************************************/
void LCD_WriteReg(uint8_t LCD_Reg, uint16_t LCD_RegValue)
{
	LCD_WR_REG(LCD_Reg);
	LCD_WR_DATA(LCD_RegValue);
}

/*****************************************************************************
 * @name       :void LCD_WriteRAM_Prepare(void)
 * @date       :2018-08-09
 * @function   :Write GRAM
 * @parameters :None
 * @retvalue   :None
 ******************************************************************************/
void LCD_WriteRAM_Prepare(void)
{
	LCD_WR_REG(lcddev.wramcmd);
}

/*****************************************************************************
 * @name       :void Lcd_WriteData_16Bit(uint16_t Data)
 * @date       :2018-08-09
 * @function   :Write an 16-bit command to the LCD screen
 * @parameters :Data:Data to be written
 * @retvalue   :None
 ******************************************************************************/
void Lcd_WriteData_16Bit(uint16_t Data)
{
#ifdef USE_DMA
    // 使用DMA传输16位数据
    LCD_SetDMAMode(mem_increase, mode_16bit);
    LCD_WriteData_DMA((uint8_t*)&Data, 1);
    LCD_SetDMAMode(mem_increase, mode_8bit);
#else
    // RGB565转RGB666格式 (RRRRRR-- GGGGGG-- BBBBBB--)
    uint8_t r5 = (Data >> 11) & 0x1F;  // 5位红色
    uint8_t g6 = (Data >> 5) & 0x3F;   // 6位绿色
    uint8_t b5 = Data & 0x1F;          // 5位蓝色
    
    // 转换为6位并左移2位对齐到高6位
    LCD_WR_DATA(((r5 << 1) | (r5 >> 4)) << 2);  // RED: 5位->6位->左移2位
    LCD_WR_DATA(g6 << 2);                        // GREEN: 6位->左移2位
    LCD_WR_DATA(((b5 << 1) | (b5 >> 4)) << 2);  // BLUE: 5位->6位->左移2位
#endif
}

/*****************************************************************************
 * @name       :void LCD_DrawPoint(uint16_t x,uint16_t y)
 * @date       :2018-08-09
 * @function   :Write a pixel data at a specified location
 * @parameters :x:the x coordinate of the pixel
				y:the y coordinate of the pixel
 * @retvalue   :None
******************************************************************************/
void LCD_DrawPoint(uint16_t x, uint16_t y)
{
	LCD_SetCursor(x, y); // 设置光标位置
	Lcd_WriteData_16Bit(POINT_COLOR);
}

/*****************************************************************************
 * @name       :void LCD_Clear(uint16_t Color)
 * @date       :2018-08-09
 * @function   :Full screen filled LCD screen
 * @parameters :color:Filled color
 * @retvalue   :None
 ******************************************************************************/
void LCD_Clear(uint16_t Color)
{
//	LCD_SetWindows(0, 0, lcddev.width - 1, lcddev.height - 1);
		LCD_SetWindows(0, 0, lcddev.width - 1, lcddev.height - 1);
#ifdef USE_DMA
    // 使用DMA填充整个屏幕
    LCD_FillColor_DMA(Color, (lcddev.width) * (lcddev.height));
#else
    // 原有方法
    LCD_CS_CLR;
    LCD_RS_SET;
    for(uint32_t i = 0; i < lcddev.width * lcddev.height; i++) {
        Lcd_WriteData_16Bit(Color);
    }
    LCD_CS_SET;
#endif
}

// /*****************************************************************************
//  * @name       :void LCD_GPIOInit(void)
//  * @date       :2018-08-09
//  * @function   :Initialization LCD screen GPIO
//  * @parameters :None
//  * @retvalue   :None
//  ******************************************************************************/
// void LCD_GPIOInit(void)
// {
	//	GPIO_InitTypeDef  GPIO_InitStructure;
	//
	//	RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB ,ENABLE);
	//
	//	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9| GPIO_Pin_10| GPIO_Pin_11| GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_15;
	//	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	//	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   //推挽输出
	//	GPIO_Init(GPIOB, &GPIO_InitStructure);
	//
	//	GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_14;
	//	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	//	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	//	GPIO_Init(GPIOB, &GPIO_InitStructure);

	// 软件 SPI 端口配置
	// GPIO_InitTypeDef GPIO_InitStruct = {0};

	// // 使能GPIOB时钟
	// __HAL_RCC_GPIOB_CLK_ENABLE();

	// // 配置PB9, PB10, PB11, PB12, PB13, PB15为推挽输出
	// GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_15; // PB9到PB15
	// GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出
	// GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上拉/下拉
	// GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
	// HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

	// // 配置PB14为上拉输入
	// GPIO_InitStruct.Pin = GPIO_PIN_14; // PB14
	// GPIO_InitStruct.Mode = GPIO_MODE_INPUT; // 输入模式
	// GPIO_InitStruct.Pull = GPIO_PULLUP; // 上拉
	// HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
// }

/*****************************************************************************
 * @name       :void LCD_RESET(void)
 * @date       :2018-08-09
 * @function   :Reset LCD screen
 * @parameters :None
 * @retvalue   :None
 ******************************************************************************/
void LCD_RESET(void)
{
	LCD_RST_CLR;
	delay_ms(100);
	LCD_RST_SET;
	delay_ms(50);
}

/*****************************************************************************
 * @name       :void LCD_Init(void)
 * @date       :2018-08-09
 * @function   :Initialization LCD screen
 * @parameters :None
 * @retvalue   :None
 ******************************************************************************/
void LCD_Init(void)
{
	// LCD 初始化流程
	// LCD_GPIOInit();//LCD GPIO初始化（已由CubeMX或HAL管理，这里不需要手动调用）

	LCD_RESET(); // 硬件复位LCD

	//************* ILI9488 初始化命令序列 **********//
	
	// 调试命令，调整接口参数
	LCD_WR_REG(0xF7);
	LCD_WR_DATA(0xA9);
	LCD_WR_DATA(0x51);
	LCD_WR_DATA(0x2C);
	LCD_WR_DATA(0x82);

	// 电源控制 - 源极驱动器电压
	LCD_WR_REG(0xC0);
	LCD_WR_DATA(0x11); // VRH
	LCD_WR_DATA(0x09); // VREG1OUT

	// 显示对比度/亮度系数
	LCD_WR_REG(0xC1);
	LCD_WR_DATA(0x41);

	// VCOM电压设置
	LCD_WR_REG(0xC5);
	LCD_WR_DATA(0x00);
	LCD_WR_DATA(0x0A);
	LCD_WR_DATA(0x80);

	// 帧率控制
	LCD_WR_REG(0xB1);
	LCD_WR_DATA(0xB0);
	LCD_WR_DATA(0x11);

	// 显示反转控制
	LCD_WR_REG(0xB4);
	LCD_WR_DATA(0x02);

	// 显示功能控制
	LCD_WR_REG(0xB6);
	// LCD_WR_DATA(0x02);
	// LCD_WR_DATA(0x42);
	LCD_WR_DATA(0x02);
	LCD_WR_DATA(0x01);
	LCD_WR_DATA(0x3B);   // 3Bh == 59, (59 + 1) * 8 = 480 

	


	// 输入模式设置
	LCD_WR_REG(0xB7);
	LCD_WR_DATA(0xC6);

	// 背光控制相关设置（特性设置，不必须）
	LCD_WR_REG(0xBE);
	LCD_WR_DATA(0x00);
	LCD_WR_DATA(0x04);

	// 设置PWM频率
	LCD_WR_REG(0xE9);
	LCD_WR_DATA(0x00);

	// // 屏幕扫描方向和RGB接口顺序设置
	// LCD_WR_REG(0x36);
	// // 参数 (1 << 3) | (0 << 7) | (1 << 6) | (1 << 5)
	// // 具体每一位说明可参考 ILI9488 手册 Memory Data Access Control 寄存器
	// LCD_WR_DATA((1 << 3) | (0 << 7) | (1 << 6) | (1 << 5));

	LCD_WR_REG(0x3A);	// 像素格式设置命令：0x3A
	LCD_WR_DATA(0x66);	// 0x55 16bit格式   0x66 18bit格式   0x77 24bit格式
	/* 正 Gamma 控制 */
	LCD_WR_REG(0xE0);
	LCD_WR_DATA(0x00);
	LCD_WR_DATA(0x07);
	LCD_WR_DATA(0x10);
	LCD_WR_DATA(0x09);
	LCD_WR_DATA(0x17);
	LCD_WR_DATA(0x0B);
	LCD_WR_DATA(0x41);
	LCD_WR_DATA(0x89);
	LCD_WR_DATA(0x4B);
	LCD_WR_DATA(0x0A);
	LCD_WR_DATA(0x0C);
	LCD_WR_DATA(0x0E);
	LCD_WR_DATA(0x18);
	LCD_WR_DATA(0x1B);
	LCD_WR_DATA(0x0F);
	/* 反 Gamma 控制 */
	LCD_WR_REG(0XE1);
	LCD_WR_DATA(0x00);
	LCD_WR_DATA(0x17);
	LCD_WR_DATA(0x1A);
	LCD_WR_DATA(0x04);
	LCD_WR_DATA(0x0E);
	LCD_WR_DATA(0x06);
	LCD_WR_DATA(0x2F);
	LCD_WR_DATA(0x45);
	LCD_WR_DATA(0x43);
	LCD_WR_DATA(0x02);
	LCD_WR_DATA(0x0A);
	LCD_WR_DATA(0x09);
	LCD_WR_DATA(0x32);
	LCD_WR_DATA(0x36);
	LCD_WR_DATA(0x0F);

	LCD_WR_REG(0x11);
	delay_ms(120);

	LCD_WR_REG(0x29);
	// 设置LCD显示方向为横屏（1=90度旋转，横屏480x320，已修正左右颠倒）
	LCD_direction(1);

//	LCD_LED = 1;	// 点亮背光
	LCD_Clear(WHITE); // 清全屏白色
}

/*****************************************************************************
 * @name       :void LCD_SetWindows(uint16_t xStar, uint16_t yStar,uint16_t xEnd,uint16_t yEnd)
 * @date       :2018-08-09
 * @function   :Setting LCD display window
 * @parameters :xStar:the bebinning x coordinate of the LCD display window
								yStar:the bebinning y coordinate of the LCD display window
								xEnd:the endning x coordinate of the LCD display window
								yEnd:the endning y coordinate of the LCD display window
 * @retvalue   :None
******************************************************************************/
void LCD_SetWindows(uint16_t xStar, uint16_t yStar, uint16_t xEnd, uint16_t yEnd)
{
	LCD_WR_REG(lcddev.setxcmd);
	LCD_WR_DATA(xStar >> 8);
	LCD_WR_DATA(0x00FF & xStar);
	LCD_WR_DATA(xEnd >> 8);
	LCD_WR_DATA(0x00FF & xEnd);

	LCD_WR_REG(lcddev.setycmd);
	LCD_WR_DATA(yStar >> 8);
	LCD_WR_DATA(0x00FF & yStar);
	LCD_WR_DATA(yEnd >> 8);
	LCD_WR_DATA(0x00FF & yEnd);

	LCD_WriteRAM_Prepare(); // 开始写入GRAM
}

/*****************************************************************************
 * @name       :void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos)
 * @date       :2018-08-09
 * @function   :Set coordinate value
 * @parameters :Xpos:the  x coordinate of the pixel
								Ypos:the  y coordinate of the pixel
 * @retvalue   :None
******************************************************************************/
void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos)
{
	LCD_SetWindows(Xpos, Ypos, Xpos, Ypos);
}

/**
 * @brief 设置 LCD 的显示方向
 * 
 * direction 参数说明：
 *   0 - 0度（默认方向，宽:LCD_W，高:LCD_H）
 *   1 - 90度旋转（宽:LCD_H，高:LCD_W）
 *   2 - 180度旋转（宽:LCD_W，高:LCD_H）
 *   3 - 270度旋转（宽:LCD_H，高:LCD_W）
 *
 * @param direction 显示方向，取值0/1/2/3
 */
void LCD_direction(uint8_t direction)
{
	lcddev.setxcmd=0x2A;
	lcddev.setycmd=0x2B;
	lcddev.wramcmd=0x2C;
	switch(direction)
	{
		case 0:
			lcddev.width=LCD_W;
			lcddev.height=LCD_H;
			LCD_WriteReg(0x36,0x08);  
			break;
			
		case 1:
			lcddev.width=LCD_H;
			lcddev.height=LCD_W;
			LCD_WriteReg(0x36,0x28); // 1110 1000
			break;
		case 2:
			lcddev.width=LCD_W;
			lcddev.height=LCD_H;
			LCD_WriteReg(0x36,0xC8); 
			break;
		case 3:
			lcddev.width=LCD_H;
			lcddev.height=LCD_W;
			LCD_WriteReg(0x36,0xA8); 
			break;
		default:
			break;
	}
}

